#include "iuCommandIfconfig.hpp"
#include <cstdio>
#include <cstring>
#include "iuApplication.hpp"
#include "iuInterface.hpp"
#include "iuMacAddress.hpp"
#include "iuIPAddress.hpp"

/**
 * @brief Recupere le nom de la commande
 * @return Renvoie le nom de la commande (ici, "ifconfig")
 */
const char *iuCommandIfconfig::getName() const
{
   static const char *name = "ifconfig";

   return name;
}

/**
 * @brief Execute la commande
 * @param numArgs le nombre d'arguments de la commande
 * @param args les arguments de la commande (args[0] est le nom de la commande)
 * @param app l'application executant la commande
 */
void iuCommandIfconfig::execute(int numArgs, char **args, iuApplication &app)
{
   //Liste les interfaces
   if ((numArgs == 1) || (numArgs == 2 && strcmp(args[1], "-a") == 0))
   {
      for (iuInterface *in = app.getInterfaces(); in; in = in->next)
      {
         if (in->isActive() || (numArgs == 2))
         {
            printf("eth%d:\n", in->getNumber());
            printf("   Port:       %d\n", in->getPort());
            printf("   MAC:        %s\n", in->getMAC().toString());
            printf("   IP:         %s\n", in->getIP().toString());
            printf("   Netmask:    %s\n", in->getNetmask().toString());
            printf("   Broadcast:  %s\n", in->getBroadcast().toString());
            printf("   MTU:        %d\n", in->getMTU());
            printf("   Active:     %d\n", in->isActive());
            printf("\n");
         }
      }
   }

   //Activation/desactivation d'une interface
   else if (numArgs == 3 && (strcmp(args[2], "up") == 0 || strcmp(args[2], "down") == 0))
   {
      int number;
      iuInterface *in;

      if (sscanf(args[1], "eth%d", &number) != 1)
      {
         printf("ifconfig: Invalid interface name\n");
         return;
      }

      if (!(in = app.getInterfaceByNumber(number)))
      {
         printf("ifconfig: No such interface\n");
         return;
      }

      in->setActive((strcmp(args[2], "up") == 0));
   }

   //Configuration de l'interface
   //Exemple: ifconfig iname w.x.y.z [netmask a.b.c.d] [broadcast j.k.l.m] [mtu nnn]
   else if (numArgs >= 3)
   {
      iuInterface *in;
      iuIPAddress ip, netmask, broadcast;
      int number;
      int mtu;
      bool netmaskFound, broadcastFound, mtuFound;

      netmaskFound = false;
      broadcastFound = false;
      mtuFound = false;

      //Lit le numero de l'interface a configurer
      if (sscanf(args[1], "eth%d", &number) != 1)
      {
         printf("ifconfig: Invalid interface name\n");
         return;
      }

      //Recupere l'interface a configurer dont le numero est number
      if (!(in = app.getInterfaceByNumber(number)))
      {
         printf("ifconfig: No such interface\n");
         return;
      }

      //Lit l'adresse IP de l'interface a configurer
      if (!(ip.fromString(args[2])))
      {
         printf("ifconfig: Invalid IP address\n");
         return;
      }

      //Lit les arguments optionnels de la commande
      for (int i = 3; i < numArgs; i++)
      {
         //Lit le masque de l'interface a configurer
         if ((strcmp(args[i], "netmask") == 0) && (i < numArgs - 1))
         {
            i++;
            netmaskFound = true;
            if (!(netmask.fromString(args[i])))
            {
               printf("ifconfig: Invalid netmask address\n");
               return;
            }
         }

         //Lit l'adresse de broadcast de l'interface a configurer
         else if ((strcmp(args[i], "broadcast") == 0) && (i < numArgs - 1))
         {
            i++;
            broadcastFound = true;
            if (!(broadcast.fromString(args[i])))
            {
               printf("ifconfig: Invalid broadcast address\n");
               return;
            }
         }

         //Lit le mtu de l'interface a configurer
         else if ((strcmp(args[i], "mtu") == 0) && (i < numArgs - 1))
         {
            i++;
            mtuFound = true;
            if (sscanf(args[i], "%d", &mtu) != 1)
            {
               printf("ifconfig: Invalid MTU value\n");
               return;
            }
         }
      }

      //Calcul du masque de reseau
      if (!netmaskFound)
      {
         if (!(ip.get() & 0x80000000))
            netmask.set(0xff000000);
         else if (!(ip.get() & 0x40000000))
            netmask.set(0xffff0000);
         else
            netmask.set(0xffffff00);
      }

      //Calcul de l'adresse de broadcast
      if (!broadcastFound)
         broadcast.set(ip.get() | ~netmask.get());

      if (!mtuFound)
         mtu = in->getMTU();

      //Configuration de l'interface
      in->configure(ip, netmask, broadcast, mtu);
   }

   //Usage incorrect
   else
   {
      printf("ifconfig: Incorrect usage:\n");
      printf("  ifconfig:           Lists the active interfaces\n");
      printf("  ifconfig -a:        Lists all the interfaces\n");
      printf("  ifconfig eth0 up:   Activates the interface eth0\n");
      printf("  ifconfig eth0 down: Deactivates the interface eth0\n");
      printf("  ifconfig eth0 10.0.0.1 [netmask 255.255.0.0] [broadcast 10.0.255.255] [mtu 800]:\n");
      printf("                      Sets the IP, netmask, broadcast and MTU of the interface\n");
   }
}
